<?php

namespace App\Traits;

use App\Exceptions\HttpErrorCode;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Arr;

trait ResourceTrait
{
    /**
     * @param LengthAwarePaginator $resource
     * @return JsonResponse
     */
    protected function toPagination(LengthAwarePaginator $resource, string $message = '成功')
    {
        $pagination = $resource->toArray();

        return response()->json([
            'code' => 0,
            'message' => $message,
            'data' => Arr::only($pagination, ['data', 'current_page', 'per_page', 'total', 'last_page', 'path']),
        ]);
    }

    /**
     * @param $data
     * @return JsonResponse
     */
    protected function success($data = [], string $message = '操作成功', int $code = 200)
    {
        if ($data instanceof Model) {
            $data = $data->toArray();
        }

        if ($data instanceof AbstractPaginator) {
            return $this->formatPaginatedResponse($data->toArray(), $message, $code);
        }

        if ($data instanceof ResourceCollection) {
            $resource = $data->resource;
            $additional = $data->additional;
            if ($resource instanceof AbstractPaginator) {
                return $this->formatPaginatedResponse(array_merge($resource->toArray(), [
                    'additional' => $additional
                ]), $message, $code);
            }
        }

        if ($data instanceof JsonResource) {
            return $this->response($this->formatData($data, $message, $code));
        }

        return $this->response($this->formatData($data, $message, $code));
    }

    /**
     * @return JsonResponse
     */
    protected function noContent($message = '操作成功')
    {
        return $this->success([], $message);
    }

    /**
     * @param string|null $message
     * @param int $code
     * @param int $statusCode
     * @param null $data
     * @return JsonResponse
     */
    public function fail(string $message = null, int $code = HttpErrorCode::SYSTEM, int $statusCode = 200, $data = null)
    {
        return response()->json([
            'code' => $code,
            'message' => $message,
            'data' => $data,
        ], $statusCode);
    }

    public function formatPaginatedResponse(array $paginated, string $message = '', $code = 200, array $headers = [], $option = 0)
    {
        $paginationInformation = $this->formatPaginatedData($paginated);
        $data = array_merge_recursive(['data' => $paginated['data']], $paginationInformation);


        return $this->response($this->formatData($data, $message, $code), $code, $headers, $option);
    }

    public function formatPaginatedData(array $paginated)
    {
        return array_merge([
            'total' => intval($paginated['total']) ?? 0,
            'page_size' => intval($paginated['per_page']) ?? 0,
            'current_page' => intval($paginated['current_page']) ?? 0,
            'total_pages' => intval($paginated['last_page']) ?? 0,
        ], Arr::get($paginated, 'additional', []));
    }

    public function formatData($data, $message, &$code)
    {
        return [
            'code' => $code,
            'message' => $message,
            'data' => $data ?: (object)$data,
        ];
    }

    public function response($data = [], int $status = 200, array $headers = [], int $options = 0): JsonResponse
    {
        return new JsonResponse($data, $status, $headers, $options);
    }
}
